package com.example.demo.controller;

import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.awt.*;
import java.time.Duration;
import java.util.UUID;

/**
 * 什么叫sse: SSE （ Server-sent Events ）是 WebSocket 的一种轻量代替方案，使用 HTTP 协议。
 * HTTP 协议是没有办法做服务器推送的，但是当服务器向客户端声明接下来要发送流信息时，客户端就会保持连接打开，SSE 使用的就是这种原理。
 * SSE 是单向通道，只能服务器向客户端发送消息，如果客户端需要向服务器发送消息，则需要一个新的 HTTP 请求。 这对比 WebSocket 的双工通道来说，会有更大的开销
 */
@RestController
public class SseController {

    @GetMapping(value = "sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> sse() {
        return Flux.interval(Duration.ofMillis(1000)).map(val -> "->" + val);
    }


    /**
     * 测试sse 服务端推送消息的字段：
     * id
     * event
     * retry
     * data
     */
    @GetMapping(value = "serverSentEvent")
    public Flux<ServerSentEvent<String>> serverSentEvent() {
        Flux<Long> longFlux = Flux.interval(Duration.ofMillis(1000));
        Flux<ServerSentEvent<String>> map = longFlux.map(val -> ServerSentEvent
                .<String>builder()
                .id(UUID.randomUUID().toString())
                .event("Test_Event")
                .data(val.toString()).build());
        return map;
    }

    /**
     * 测试EventSource  服务端向客户端推送数据时候，客户端eventSource触发以下方法
     * <p>
     * onopen()
     * onmessage()
     * onerror()
     *
     * @CrossOrigin: 跨域注解，保证前端在别的地方可以访问到
     */
    @CrossOrigin
    @GetMapping(value = "eventSource")
    public Flux<ServerSentEvent<String>> eventSource() {
        Flux<Long> longFlux = Flux.interval(Duration.ofMillis(1000));
        Flux<ServerSentEvent<String>> map = longFlux.map(val -> ServerSentEvent
                .<String>builder()
                .id(UUID.randomUUID().toString())
                .event("Test_Event")
                .data(val.toString()).build());
        return map;
    }

}
